/*
	Alan Fortes 
	CPE 301
	DA 5, part 3
	
	The following C program uses an ATMega328p to
	control the angular position of a servo motor.
	
	This is done by using a voltage divider, with the 
	resistor near ground being a potentiometer to, 
	produce a varying voltage from the middle of the
	voltage divider. This voltage is then fed into 
	the PC0(ADC0) pin, and converted into a value 
	using ADC conversion. The values taken from the 
    ADC register are then placed into an equation to
	find the appropriate value to place in the OCR1A
	register, to produce a PWM that will change the 
	angle that the servo will turn to. 
	
	Through experimentation, the following, OCR1A values
	have been found to produce the following servo angles,
	using a standard coordinate grid system:

		OCR1A | Servo Angle
		600   | 0
		1025  | 45
		1450  | 90
		1875  | 135
		2300  | 180
					   90*						
						|    /
						|   /
						|  /
						| /
		180*____________|/_______________0*
						|
						|
						|
						|
						|
					   270*
		
	By using the serial display capabilities of the ATMega328p,
	I have found that the values that the ADC produces range from
	about 40 to 540. To find the equation that determines the 
	OCR1A value that corresponds to the ADC value, we must work
	backwards:
	
	An ADC value of 50, and below to ensure that the motor does not get
	forced below 0 degrees, must produce an OCR1A value of 600. To 
	accomplish this, the equation so far will be the ADC value minus
	70, plus 600. 
	
	(ADC - 50) + 600.  
	
	However, if the value reaches any value 540 or above, a value of 
	2300 must be given. To find this, we must set our current equation
	to 2300, our maximum ADC value, set the value of ADC to be 540, the 
	maximum ADC value, and multiply the ADC - 70 part by a factor to be 
	able to reach 2300.
	
	(540 - 50) * X + 600 = 2300, 490 * X = 1700, X = 3.469 = 3.47
	
	The final equation to convert the ADC value to a suitable OCR1A
	value is: (ADC - 50) * 3.47 + 600
	
	Another detail that must be taken into consideration is errant voltage
	being input to the ADC pin, from the voltage divider, that would cause
	the servo to twitch. 
	
	To ensure that only user input, substantial changes to the ADC value,
	would cause the value of OCR1A to change, we must store the current 
	value of ADC in a variable, and compare this current value to all 
	new ADC values. If the new ADC value is greater or less than 15, 
	since the ADC value fluctuates between increases and decreases of 
	about 10 points, then the value of the current ADC value variable 
	will be replaced with the new ADC value. The value of the current 
	value variable will be placed inside of OCR1A.
*/

#define F_CPU 8000000UL
#include <avr/io.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include <util/delay.h>

int main(void)
{
	
	DDRC=0x00;          //The C port is initialized to be 0 to all the C port receive input.
	int currentADC = 0; //This is the ADC value that the code has locked in to preven the
	                    //motor from twitching. 
	int differenceADC = 0; //This variable stores the difference between the incoming
						   //ADC values and the current ADC value.
	
	DDRB=0xFF; //The pins of port B are set to be output.
	ADCSRA = 0x82; //The ADC conversion is set to run, along with an appropriate prescaler. 
 
	double adcValue;
	int ocrValue;

	ICR1=19999; //The ICR1 Register is given a value to set the right period and the appropriate 
	            //bits for the TCCR1A and TCCR1B registers are set.
	TCCR1A|=(0<<COM1A0)|(1<<COM1A1)|(0<<COM1B0)|(0<<COM1B1)|(0<<FOC1A)|(0<<FOC1B)|(1<<WGM11)|(0<<WGM10);
	TCCR1B|=(0<<ICNC1)|(0<<ICES1)|(1<<WGM13)|(1<<WGM12)|(0<<CS12)|(1<<CS11)|(0<<CS10);

	while(1) //This infinite loop constantly receives the ADC input from the potentiometer. 
	{
		ADCSRA |= (1<<ADSC); //
		while((ADCSRA&(1<<ADIF))==0){		
		}
		differenceADC = currentADC - ADC; 

if((differenceADC > 15) || (differenceADC < -15)){ //To ensure that errant changes in voltage do not 
	                                               //make the servo motor twitch, the change must be
	currentADC = ADC;                              //great enough to be acknowledged.
	
 }
			if(currentADC < 50){ //If the position is below the 50 ADC mark, then the value of ocrValue
				                  //is made to be 600, so that it may not go below 0 degrees.
				ocrValue = 600;

				} else if(currentADC > 540){ //If the position has reached 540 or above, the ocrValue is 
										     //set to be 2300 so that it may not go beyond 180 degrees.				
				ocrValue = 2300;
				
				}else{
				adcValue = ((currentADC - 50) * 3.47) + 600; //If the value of currentADC is between the extremes,
				ocrValue = adcValue;						 //the appropriate value is given to correspond to the 
		}                                                    //correct angle.
		
		 OCR1A = ocrValue;			
		
	}
}
